/*
   Copyright (c) 2023 李伟国
   shiro-learner is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details. 
*/

package cn.platform.service.impl;


import cn.platform.config.properties.ConfigShiroProperties;
import cn.platform.config.properties.ConfigUploadProperties;
import cn.platform.constant.RedisConstant;
import cn.platform.constant.enumeration.StatusConstantEnum;
import cn.platform.dto.ChangePasswordDto;
import cn.platform.dto.LoginDto;
import cn.platform.entity.Role;
import cn.platform.entity.User;
import cn.platform.mapper.UserMapper;
import cn.platform.service.IEmailService;
import cn.platform.service.ILoginService;
import cn.platform.service.IRoleService;
import cn.platform.service.IUserRoleService;
import cn.platform.utils.JWTUtil;
import cn.platform.utils.RedisUtil;
import cn.platform.utils.StringUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
public class LoginServiceImpl implements ILoginService {
    private static final Logger log = LoggerFactory.getLogger(LoginServiceImpl.class);
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IEmailService emailService;

    @Autowired
    private ConfigShiroProperties configShiroProperties;

    @Autowired
    private IUserRoleService userRoleService;

    @Autowired
    private IRoleService roleService;

    @Override
    public String login(LoginDto loginDto, HttpServletRequest request) {
        User user = userMapper.selectByUsername(loginDto.getUsername());
        String redisKey = String.valueOf(redisUtil.get(RedisConstant.LOGIN_VERIFICATION.getValue() + loginDto.getKaptchaOwner()));
        System.out.println(redisKey);
        System.out.println(loginDto.getKaptcha());
        if(redisKey == null ){
            throw new AuthenticationException("验证码过期");
        }
        else if(!redisKey.equalsIgnoreCase(loginDto.getKaptcha())){
            throw new AuthenticationException("验证码不匹配");
        }
        if(user == null){
            throw new AuthenticationException("无此用户");
        }
        if(!user.getPassword().equals(StringUtil.getMd5(loginDto.getPassword()+user.getSalt()))){
            throw new AuthenticationException("密码错误");
        }
        if(user.getStatus().equals(StatusConstantEnum.FREEZED.getCode())){
            throw new AuthenticationException("账号未激活，请留意邮箱激活邮件");
        }
        long currentTimeMillis = System.currentTimeMillis();
        log.info(String.valueOf(System.currentTimeMillis()));
        String token = JWTUtil.createToken(user.getSalt(),user.getUsername(),user.getId(), currentTimeMillis);
        // loginToken : username
        redisUtil.set(RedisConstant.LOGIN_USER.getValue()+token,loginDto.getUsername(),60*30);
        return token;
    }

    @Override
    public void logout(HttpServletRequest req) {
        String accessToken = req.getHeader(RedisConstant.TOKEN_HEADER_LOGIN.getValue());
        String username = JWTUtil.getUsername(accessToken);
        // 删除 loginToken
        redisUtil.del(RedisConstant.LOGIN_USER.getValue()+accessToken);
        log.info("推出登录");
    }

    @Override
    public boolean active(String activeCode) {
        String username = String.valueOf(redisUtil.get(RedisConstant.REGISTER_ACTIVE_CODE.getValue()+activeCode));
        if(ObjectUtils.isEmpty(username)){
            throw  new AuthenticationException("激活码无效");
        }
        long expire = redisUtil.getExpire(RedisConstant.REGISTER_ACTIVE_CODE.getValue() + activeCode);
        if(expire>60*5){
            redisUtil.set(RedisConstant.REGISTER_ACTIVE_CODE.getValue()+activeCode, username, 60*5);
        }
        User user = userMapper.selectByUsername(username);
        Role role = roleService.findByName(configShiroProperties.getNewRegisterUserBindRole());
        List<Long> a = new ArrayList<>();
        a.add(role.getId());
        userRoleService.bindByUserIdRoleIds(user.getId(), a);
        return userMapper.updateStatusById(StatusConstantEnum.ENABLE.getCode(), user.getId()) > 0;
    }

    /**
     * 发送验证码
     *
     * @return 验证码标识
     */
    @Override
    public String sendCheckCode(String username) {
        if(ObjectUtils.isEmpty(username)){
            throw new UnauthenticatedException("账号为空");
        }
        String s = UUID.randomUUID().toString().replaceAll("-","");
        Random random = new Random();
        int randomNumber = random.nextInt(9000) + 1000;
        User user = userMapper.selectByUsername(username);
        if(ObjectUtils.isEmpty(user)){
            throw new UnauthenticatedException("账号不存在");
        }
        String email = user.getEmail();
        Thread thread = new Thread(){
            public void run(){
                emailService.sendEmailVerificationCode(randomNumber,email);
            }
        };
        thread.start();
        redisUtil.set("learner:user:change:password:"+s,randomNumber,10*60);
        return s;
    }

    @Override
    public void changePassword(ChangePasswordDto changePasswordDto) {
        String code = String.valueOf(redisUtil.get("learner:user:change:password:"+changePasswordDto.getCodeOwner()));
        if(ObjectUtils.isEmpty(code)){
            throw new UnauthenticatedException("验证失败");
        }
        System.out.println(changePasswordDto.toString());
        if(!code.equals(changePasswordDto.getCode())){
            throw new UnauthenticatedException("验证码错误，请重新输入");
        }
        User user = userMapper.selectByUsername(changePasswordDto.getUsername());
        user.setPassword(StringUtil.getMd5(changePasswordDto.getPassword()+user.getSalt()));
        userMapper.updateById(user);
    }

    @Override
    public boolean register(User user) {
        // 设置盐
        user.setSalt(UUID.randomUUID().toString().substring(0,5));
        // 设置密码
        user.setPassword(StringUtil.getMd5(user.getPassword() + user.getSalt()));
        // 设置账号状态
        user.setStatus(StatusConstantEnum.FREEZED.getCode());
        // 配置默认头像
        int randomInt = new Random().nextInt(1001);
        user.setHeadUrl("https://static.nowcoder.com/head/"+randomInt+"m.png");
        // 存入用户
        int insert = userMapper.insert(user);
        // 配置激活码
        String active_code = UUID.randomUUID().toString().replaceAll("-", "");
        redisUtil.set(RedisConstant.REGISTER_ACTIVE_CODE.getValue()+active_code, user.getUsername(), 60*60*24*30);
        // 发邮件
        Thread sendEmail = new Thread(){
            @Override
            public void run() {
                super.run();
                emailService.sendEMailActivationUrl("http://127.0.0.1:8134/active/"+active_code, user.getEmail());
            }
        };
        sendEmail.start();
        return insert > 0;
    }

}
